﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace NMF.Languages.Adaption
{
    [DebuggerDisplay("{Name}")]
    public class AdaptiveClass : IClass
    {
        public PropertyCollection Properties { get; private set; }
        private List<AdaptiveClass> baseTypes;
        private string typeName;
        private AdaptiveTypeSystem typeSystem;

        public AdaptiveClass(string name, AdaptiveTypeSystem typeSystem)
        {
            this.typeName = name;
            this.typeSystem = typeSystem;
            Properties = new PropertyCollection();
            baseTypes = new List<AdaptiveClass>();
        }

        public AdaptiveClass(string name, AdaptiveClass parent) : this(name, parent.typeSystem) { }

        public IProperty GetProperty(string name)
        {
            if (!Properties.Contains(name))
            {
                Properties.Add(new AdaptiveProperty(this, name));
            }
            return Properties[name];
        }

        public object CreateInstance()
        {
            return new AdaptiveInstance(this);
        }

        public IEnumerable<IProperty> GetProperties()
        {
            return Properties;
        }

        public IEnumerable<IClass> GetBaseTypes()
        {
            return baseTypes;
        }

        public ITypeSystem TypeSystem
        {
            get { return typeSystem; }
        }

        public void AssertIsAssignableFrom(IClass baseClass)
        {
            var baseClassCasted = baseClass as AdaptiveClass;
            if (baseClassCasted == null) throw new AssertionException();
            if (!baseTypes.Contains(baseClassCasted)) baseTypes.Add(baseClassCasted);
        }

        public string Name
        {
            get { return typeName; }
        }


        public event EventHandler InstanceCreated;


        public void Visit(ITypeVisitor visitor)
        {
            visitor.VisitClass(this);
        }

        public T Visit<T>(ITypeVisitor<T> visitor)
        {
            return visitor.VisitClass(this);
        }

        public T Visit<S, T>(ITypeVisitor<S, T> visitor, S parameter)
        {
            return visitor.VisitClass(this, parameter);
        }
    }
}
